//
//  NSObject+category.m
//  AwesRecorder
//
//  Created by LenTi on 2019/8/27.
//  Copyright © 2019 VoiceRecorder. All rights reserved.
//

#import "NSObject+category.h"
#import <objc/runtime.h>

@implementation NSObject (category)

- (void) setUniqueSerialString_:(NSString *)value {
    
    objc_setAssociatedObject(self, @selector(uniqueSerialString_), value, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *) uniqueSerialString_ {
    
    NSString *value = objc_getAssociatedObject(self, @selector(uniqueSerialString_));
    
    if (!value) {
        
        value = [NSObject randomUniqueSerialString_];
        [self setUniqueSerialString_:value];
    }
    
    return value;
}

+ (NSString *) randomUniqueSerialString_ {
    
    int length = 12;
    
    char data[length];
    
    for (int i=0;i<length;i++) {
        
        data[i] = (char)('A' + (arc4random_uniform(26)));
    }
    
    return [[NSString alloc] initWithBytes:data length:length encoding:NSUTF8StringEncoding];
}

- (id) performSelector:(SEL)aSelector withObjects:(NSArray *)objects {
    
    NSMethodSignature *methodSignature = [[self class] instanceMethodSignatureForSelector:aSelector];
    
    if(methodSignature == nil) {
        
        @throw [NSException exceptionWithName:@"Error" reason:@"Not this function." userInfo:nil];
        return nil;
        
    } else {
        
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
        [invocation setTarget:self];
        [invocation setSelector:aSelector];
        
        //签名中方法参数的个数，内部包含了self和_cmd，所以参数从第3个开始
        NSInteger  signatureParamCount = methodSignature.numberOfArguments - 2;
        NSInteger requireParamCount = objects.count;
        NSInteger resultParamCount = MIN(signatureParamCount, requireParamCount);
        for (NSInteger i = 0; i < resultParamCount; i++) {
            id  obj = objects[i];
            [invocation setArgument:&obj atIndex:i+2];
        }
        [invocation invoke];
        
        //返回值处理
        id callBackObject = nil;
        if(methodSignature.methodReturnLength) {
            [invocation getReturnValue:&callBackObject];
        }
        
        return callBackObject;
    }
}

@end
